home *** CD-ROM | disk | FTP | other *** search
- /********************************************************
- ** Events.c: Handle user events coming from all sides. **
- ** Written by T.Pierron **
- ** 10-Dec-1999 **
- ********************************************************/
-
- /* All the necessary includes: */
- #include <intuition/intuition.h> /* Std datatypes */
- #include <intuition/intuitionbase.h> /* To access ActiveScreen */
- #include <intuition/screens.h> /* Screen information */
- #include <graphics/rastport.h> /* Rastport info */
- #include <graphics/gfxbase.h> /* DefaultFont */
- #include <graphics/text.h> /* struct TextFont */
- #include <libraries/gadtools.h> /* NewMenus and NewGadget */
- #include <libraries/commodities.h> /* Commodity datatypes */
- #include <libraries/dos.h> /* CTRL/C signal */
- #include <devices/inputevent.h> /* For raw keymap conversion */
-
- #include "cmap.h"
- #define CATCOMP_STRINGS /* We only need strings */
- #include "cmap_strings.h" /* Support of locale.library */
-
- /* External variables: */
- extern struct IntuitionBase *IntuitionBase;
- extern struct GfxBase *GfxBase;
- extern struct Library *IconBase;
- extern struct Window *window;
- extern struct Screen *screen;
- extern struct NewMenu newmenu[],*checked,*checkset;
- extern struct Gadget *gad, *copy_gad, *paste_gad;
- extern struct NewWindow new_window;
- extern struct TextFont *font,*newfont;
- extern struct Menu *menu;
- extern WORD xdeb,ydeb,xfin,yfin,X,Y; /* ASCII Table position */
- extern UBYTE MaxWid,Font_height,Char[]; /* Font information */
- extern ULONG BoxTags[],sigwin;
- extern UBYTE CharsetNum, VertSort;
-
-
- struct TTextAttr *aslfont; /* Returned by the ASL font requester */
- struct MsgPort *broker_mp = NULL; /* Commodity message port */
- CxObj *broker, *filter; /* Commodity and hot-key */
- CxMsg *msg; /* To collect messages */
- UBYTE *StrBuf; /* Shortcut to string gadget's buffer */
- struct IntuiMessage message;
-
- struct InputEvent ie = {0,IECLASS_RAWKEY}; /* Keyboard translation map */
-
- BYTE CloseQuit=TRUE; /* True is close gadget quit the prog */
- BYTE IsDraw=0,PopWin=TRUE; /* State of the recessed box */
- WORD NumChar=-1,CustDx=0; /* Selected character number */
- ULONG cxsigflag=0; /* Signal bits of the commo. */
-
- struct NewBroker newbroker = {
- NB_VERSION,
- "CharMap", /* String to identify this commo. */
- MSG_DESCLINE1_STR,
- MSG_DESCLINE2_STR,
- NBU_UNIQUE | NBU_NOTIFY | /* Don't want any new commodities starting with this name. */
- COF_SHOW_HIDE, /* If someone tries it, let me know */
- 0, 0, 0, 0
- };
-
- void Free_commodity();
- void Handle_gadget(struct Gadget *);
-
- /*** Initialize the message port of the commodity: ***/
- BOOL Init_commodity(int argc, char *argv[])
- {
- UBYTE *hotkey, **ttypes;
-
- if(broker_mp = (void *) CreateMsgPort())
- {
- newbroker.nb_Port = broker_mp;
- cxsigflag = 1L << broker_mp->mp_SigBit;
-
- /* Get the tool-type or command line value: */
- ttypes = (UBYTE **) ArgArrayInit(argc, argv);
- newbroker.nb_Pri = (BYTE)ArgInt(ttypes, "CX_PRIORITY", 0);
- CharsetNum = (BYTE)ArgInt(ttypes, "CHARSET", 2);
- hotkey = (UBYTE *) ArgString(ttypes, "HOTKEY", "rawkey lalt control c");
- CloseQuit = ArgString(ttypes, "CLOSEQUIT", NULL)==NULL ? FALSE:TRUE;
- VertSort = ArgString(ttypes, "HORIZONTALSORT", NULL)==NULL ? TRUE:FALSE;
- Parse_geometry( (UBYTE *)ArgString(ttypes, "GEOMETRY", ",,,") );
-
- /* Whould the user show immediatly the window ? */
- if( !Stricmp(ArgString(ttypes, "CX_POPUP", Char), "NO") ) PopWin=FALSE;
-
- if(broker = (void *) CxBroker(&newbroker, NULL))
- {
- /* HotKey() is an amiga.lib function that creates a filter, sender */
- /* and translate CxObject and connects them to report a hot key */
- /* press and delete its input event. */
- if(filter = (void *) HotKey(hotkey, broker_mp, EVT_HOTKEY))
- {
- AttachCxObj(broker, filter); /* Add a CxObject to another's personal list */
-
- if(! CxObjError(filter))
- ActivateCxObj(broker, 1L); /* All done! */
- }
- }
- ArgArrayDone(); /* this amiga.lib function cleans up after ArgArrayInit() */
- }
- return (BOOL)(broker && broker_mp);
- }
-
- void Free_commodity( void )
- {
- /* DeleteCxObjAll() is a commodities.library function that not only **
- ** deletes the CxObject pointed to in its argument, but deletes all of **
- ** the CxObjects attached to it. */
- if(broker)
- {
- DeleteCxObjAll(broker);
-
- /* Empty the port of all CxMsgs */
- while(msg = (CxMsg *)GetMsg(broker_mp))
- ReplyMsg((struct Message *)msg);
- }
-
- if(broker_mp) DeletePort(broker_mp);
- }
-
- WORD OldX=0,OldY=0,Xc=0,Yc=0;
- /*** Move the sunken box while dragging the mouse with LMB down: ***/
- void Handle_box( void )
- {
- extern WORD txtpen, fillpen, filltxt;
- extern struct RastPort *RP;
- extern UBYTE CharWid[], NumChars;
- WORD sunken=FALSE;
-
- /* Center mouse position on top-left corner of the box: */
- if(X<xdeb) X=0; else X -= (X-xdeb)%MaxWid;
- if(Y<ydeb) Y=0; else Y -= (Y-ydeb)%Font_height;
-
- /* If it isn't already drawn... */
- IsDraw=PRESSED;
- if(X==OldX && Y==OldY) return;
- BoxTags[2] = TAG_DONE;
-
- /* ...and inside area */
- if(OldX>=xdeb && OldX<xfin && OldY>=ydeb && OldY<yfin)
- {
- /* Draw the sunken / beveled box: */
- DR:SetAPen(RP,sunken?fillpen : 0);
- RectFill(RP,OldX+1,OldY+1,OldX+MaxWid-2,OldY+Font_height-2);
- SetAPen(RP,sunken?filltxt : txtpen);
- Move(RP,OldX+(MaxWid-CharWid[NumChar]>>1),OldY+font->tf_Baseline+2);
- *Char=(CharsetNum==3 && NumChar==127 ? 32:NumChar);
- Text(RP,Char,1);
-
- DrawBevelBoxA(RP,OldX,OldY,MaxWid,Font_height,BoxTags);
- }
-
- if(sunken) { Disp_charinfo(NumChar); return; } OldX=X; OldY=Y;
-
- if(X>=xdeb && X<xfin && Y>=ydeb && Y<yfin) {
- BoxTags[2] = GTBB_Recessed;
- NumChar = VertSort ? ((X-xdeb)/MaxWid<<3)+(Y-ydeb)/Font_height :
- ((Y-ydeb)/Font_height*NumChars)+(X-xdeb)/MaxWid;
- if(CharsetNum >1) NumChar+=32;
- if(CharsetNum==3 && NumChar>127) NumChar+=160-128;
- sunken=TRUE; Xc=X; Yc=Y; goto DR;
- } else {
- NumChar=-1;
- IsDraw=OUTSIDE_AREA;
- }
- }
-
- /*** Move the box using the keyboard: ***/
- void Handle_keyboard(UWORD code)
- {
- /* To prevent that keyboard doesn't disturb the mouse: */
- if(IsDraw > 0 || code<76 || code>79) return;
- if(Xc)
- {
- /* Rawkey code for arrow keys: */
- switch(code)
- {
- case 76: Yc -= Font_height; break;
- case 77: Yc += Font_height; break;
- case 78: Xc += MaxWid; break;
- case 79: Xc -= MaxWid; break;
- }
- /* Check if cursor overrun the map: */
- if(VertSort) {
- /* Increase/decrease x pos, if cursor reach bottom/top of table: */
- if(Yc< ydeb) { Yc=yfin-Font_height; Xc-=MaxWid; }
- if(Yc>=yfin) { Yc=ydeb; Xc+=MaxWid; }
- if(Xc< xdeb) Xc=xfin-MaxWid;
- if(Xc>=xfin) Xc=xdeb;
- } else {
- if(Xc< xdeb) { Xc=xfin-MaxWid; Yc-=Font_height; }
- if(Xc>=xfin) { Xc=xdeb; Yc+=Font_height; }
- if(Yc< ydeb) Yc=yfin-Font_height;
- if(Yc>=yfin) Yc=ydeb;
- }
- } else {
- /* If cursor hasn't been moved yet: */
- Xc=xdeb; Yc=ydeb;
- }
- X=Xc; Y=Yc;
- Handle_box();
- /* To prevent mouse doesn't disturb the keyboard: */
- IsDraw=KEYB_CONTROL;
- }
-
- /*** Processes menus events: ***/
- void Handle_menu( LONG MenuID )
- {
- extern struct EasyStruct Request;
- extern ULONG FontTags[];
- extern UBYTE *GadTxt[];
-
- /** I apologize for this very bad example of ***
- *** obfuscated C programming style. **/
- switch( MenuID )
- {
- /**** Project Menu ****/
-
- case 111:/* Look if the first item isn't already selected: */
- if(checked == &newmenu[NM_FONTTYPE]) break;
- /* Take the font of the screen (Please, don't close it!): */
- font = screen->RastPort.Font; goto check;
- case 112:/* Ditto: */
- if(checked == &newmenu[NM_FONTTYPE+1]) break;
- font = GfxBase->DefaultFont;
- check: /* Menus will be reallocated, change NewMenus struct. directly: */
- checked->nm_Flags &= ~CHECKED;
- checked = &newmenu[ MenuID-111+NM_FONTTYPE ];
- checked->nm_Flags |= CHECKED;
- /* Adjust cycle font-type entries: */
- if( CustDx = (FontTags[3] = MenuID-111)==2 ) FontTags[3]=0;
- FontTags[1] = (ULONG) &GadTxt[GT + (CustDx ? 0:1)];
- /* Change the charset depending of the font: */
- Init_charset(font);
- MenuID = CharsetNum+140;
- goto charset;
- REDOIT: MenuID = 113;
- case 113:/* Open a ASL requester: */
- if( aslfont = (struct TTextAttr *) open_asl() )
- {
- if( newfont ) CloseFont(newfont);
- if( newfont=(void *)OpenDiskFont(aslfont) )
- {
- font = newfont;
- goto check;
- }
- }
- /* Cancel the menu selection (sorry, I don't want to use temporary variables) */
- ((struct MenuItem *)ItemAddress(menu,MENUITEM(0,0,2)))->Flags &= ~CHECKED;
- ((struct MenuItem *)ItemAddress(menu,MENUITEM(0,0,checked-&newmenu[NM_FONTTYPE])))->Flags |= CHECKED;
-
- if(message.Class==GADGETUP) GT_SetGadgetAttrsA(message.IAddress,window,NULL,FontTags);
- break;
- /* Changing the charset of ASCII table: */
- case 141:if(checkset == &newmenu[NM_CHARSET]) break; goto charset;
- case 142:if(checkset == &newmenu[NM_CHARSET+1]) break; goto charset;
- case 143:if(checkset == &newmenu[NM_CHARSET+2]) break;
-
- charset: checkset->nm_Flags &= ~CHECKED;
- checkset = &newmenu[ MenuID-141+NM_CHARSET ];
- CharsetNum = MenuID-140;
- checkset->nm_Flags |= CHECKED;
- /* Now, we can reopen our window: */
- goto new_win;
-
- case 21: Handle_gadget(copy_gad);
- case 24: /* Clear the text contained in the string gadget: */
- StrBuf[0]=0; RefreshGList(gad, window, NULL, 1);
- break;
- case 25: /* Jump to the next screen: */
- if( !screen->NextScreen ) break;
- screen = screen->NextScreen;
- /* Adjust the screen font, to what the screen uses: */
- if(checked == &newmenu[NM_FONTTYPE]) font = screen->RastPort.Font;
- new_win: cleanup(NULL,-1);
- /* If init failed, try to see if we can changed the font again: */
- if( setup() ) goto REDOIT;
- /* Before to move the screen, wait all it's OK: */
- ScreenToFront(screen);
- break;
- case 15: /* About menu entry: */
- EasyRequest(window, &Request, 0, CHARMAP_VERSION); break;
- case 16: /* Minimize/Normalize the window: */
- ZipWindow(window);
- break;
- case 17: cleanup(NULL,-1); return; /* Hide */
- case 18: cleanup(NULL,0); /* Quit */
-
- /**** Edit Menu ****/
- case 22: Handle_gadget(copy_gad); break;
- case 23: Handle_gadget(paste_gad); break;
- case 26: VertSort=((struct MenuItem *)ItemAddress(menu,MENUITEM(1,5,0)))->Flags & CHECKED ? 1:0;
- IsDraw = NOT_PRESSED;
- Draw_ASCIIChart(); /* Sorting */
- }
- if(window==NULL) cleanup(0,0);
- }
-
- /*** Handle all messages comming from a commo: ***/
- void Handle_commo(void)
- {
- ULONG msgid, msgtype;
-
- /* The signal is comming from a commodity: */
- while(msg = (CxMsg *)GetMsg(broker_mp))
- {
- msgid = CxMsgID(msg);
- msgtype = CxMsgType(msg);
- ReplyMsg((struct Message *)msg);
-
- switch(msgtype)
- {
- case CXM_IEVENT:
- /* Display or move the window, in the front-most screen: */
- if(msgid == EVT_HOTKEY)
- {
- front_most_screen:
- screen = IntuitionBase->ActiveScreen;
- /* If the window is already open, but not in the front-most screen, close it: */
- if(window)
- if(window->WScreen != screen) cleanup(NULL,-1);
- else {
- /* Activate and move it to front: */
- WindowToFront(window);
- ActivateWindow(window);
- /* If the window is minimize, normalize it: */
- if(window->Height<=window->BorderTop) ZipWindow(window);
- break;
- }
-
- /* The screen font can be changed: */
- if(checked == &newmenu[NM_FONTTYPE]) font = screen->RastPort.Font;
- /* If something goes wrong, change the font: */
- if( setup() ) Handle_menu(113);
- ScreenToFront(screen);
- }
- break;
- case CXM_COMMAND:
- switch(msgid)
- {
- case CXCMD_DISABLE:
- /* If user want to disable the commo, minimize the window: */
- if(window && window->Height>window->BorderTop) ZipWindow(window);
- ActivateCxObj(broker, 0L);
- break;
- case CXCMD_ENABLE:
- /* If user want to enable the commo, normalize it: */
- if(window && window->Height<=window->BorderTop) ZipWindow(window);
- ActivateCxObj(broker, 1L);
- break;
-
- case CXCMD_APPEAR:
- /* Screen can have changed: */
- goto front_most_screen;
-
- case CXCMD_DISAPPEAR:if(window) cleanup(NULL,-1); break;
- case CXCMD_KILL:
- case CXCMD_UNIQUE:
- /* Commodities Exchange can be told not only to refuse to launch a **
- ** commodity with a name already in use but also can notify the **
- ** already running commodity that it happened. It does this by **
- ** sending a CXM_COMMAND with the ID set to CXMCMD_UNIQUE. If the **
- ** user tries to run a windowless commodity that is already running, **
- ** the user wants the commodity to shut down. */
- cleanup(0,0);
- }
- }
- }
- }
-
- /*** Handle gadget messages ***/
- void Handle_gadget( struct Gadget *G )
- {
- extern void *clipdev;
- extern UBYTE GadDisable;
-
- /* If clipboard is unavailable: */
- if((G==copy_gad || G==paste_gad) && !clipdev && !(clipdev=(void *)CBOpen(0))) {
- /* Disable all related entries: */
- register int i;
- for(i=0; i<3; i++) {
- OffMenu(window, SHIFTMENU(1)+SHIFTITEM(i)+SHIFTSUB(NOSUB));
- newmenu[16+i].nm_Flags |= NM_ITEMDISABLED;
- }
- OffGadget(copy_gad, window, NULL);
- OffGadget(paste_gad, window, NULL);
- GadDisable |= 6;
- return;
- }
-
- switch(G->GadgetID)
- {
- case 0: /* Clear everything in the string gadget */
- Handle_menu(24);
- break;
- case 1: /* Copy string into clipboard: */
- CBWriteFTXT(clipdev, StrBuf);
- break;
- case 2: /* Read string from clipboard: */
- if( CBQueryFTXT(clipdev) )
- {
- CBReadCHRS(clipdev, StrBuf, sti(gad)->MaxChars);
- RefreshGList(gad, window, NULL, 1);
- }
- case 3: /* Type of a font */
- Handle_menu(111+message.Code-CustDx);
- break;
- case 4: /* Choose a different Charset via the cycle gadget */
- Handle_menu(141+message.Code);
- break;
- case 10: /* String gadget realease: show info of character */
- if(sti(gad)->NumChars == 1)
- Disp_charinfo( StrBuf[0] );
- }
- }
-
- /**** Main loop, which collects and distributes all messages: ****/
- void handle_input(void)
- {
- static UBYTE buffer[8],drawit;
- ULONG sigrcvd;
-
- FOREVER {
- Deb: sigrcvd = Wait(SIGBREAKF_CTRL_C | cxsigflag | sigwin);
-
- /* Look from where the signal comes: */
- if(sigrcvd & SIGBREAKF_CTRL_C) cleanup(0,0);
-
- if(sigrcvd & cxsigflag) Handle_commo();
-
- if((sigrcvd & sigwin) == 0) continue;
-
- drawit=FALSE;
- /* Use the new GadTools GT_GetIMsg() function to get input events */
- while (msg = (void *) GT_GetIMsg(window->UserPort))
- {
- /* Copy entire message: */
- CopyMem(msg,&message,sizeof(message));
- X=message.MouseX; Y=message.MouseY;
-
- if( message.Class == MENUVERIFY && message.Code == MENUHOT && IsDraw )
- {
- /* Just clears cursor */
- ((struct IntuiMessage *)msg)->Code=MENUCANCEL;
- message.Class=MOUSEBUTTONS;
- }
-
- /* Reply to the message */
- GT_ReplyIMsg(msg);
-
- switch(message.Class)
- {
- /* The close-window gad. simply hide the main window: */
- case CLOSEWINDOW: cleanup(NULL,CloseQuit ? 0:-1);
- case MOUSEBUTTONS:
- switch(message.Code)
- {
- /* Draw a recessed box below the mouse: */
- case SELECTDOWN: Handle_box(); break;
- /* Clear the box and add the char. in string gadget: */
- case SELECTUP:
- if(IsDraw) {
- INS:if(NumChar>=0 && IsDraw) {
- struct StringInfo *st = sti(gad);;
-
- if(st->NumChars>=st->MaxChars-1) strcpy(StrBuf, StrBuf+1);
-
- strcat(st->Buffer,Char);
- RefreshGList(gad, window, NULL, 1);
- /* If char has been keyed in, don't clear the cursor: */
- if(IsDraw==KEYB_CONTROL) break;
- }
- Xc=X; Yc=Y; CL:X=Y=0; Handle_box(); IsDraw=NOT_PRESSED; drawit=0;
- } break;
- case MENUHOT: goto CL;
- }
- break;
-
- case MOUSEMOVE: if(IsDraw>0) drawit=1; break;
-
- case MENUPICK:
- { struct MenuItem *menuitem;
- ULONG MenuNum;
-
- while (message.Code != MENUNULL)
- {
- menuitem = (struct MenuItem *) ItemAddress(menu,message.Code);
- MenuNum = (ULONG) GTMENUITEM_USERDATA(menuitem);
- Handle_menu( MenuNum );
- message.Code = (MenuNum<100 ? menuitem->NextSelect:MENUNULL);
- }
- } break;
-
- case RAWKEY: /* Rawkey which will be Translated */
- /* If the rawkey code can be processed, don't translate it: */
- if(message.Code>127) break;
- Handle_keyboard(message.Code);
-
- ie.ie_Code = message.Code;
-
- /* Make sure deadkeys and qualifiers are take into account: */
- ie.ie_EventAddress = *((APTR *)message.IAddress);
- ie.ie_Qualifier = message.Qualifier;
-
- /* Map RAWKEY to ANSI */
- if(MapRawKey(&ie, buffer, sizeof(buffer), NULL) <= 0) break;
- { register UBYTE code = *buffer;
-
- /* Space bar inserts the highlighted char in the string gadget: */
- if(code==' ' || code=='\r') goto INS;
- if(code==27 && IsDraw) goto CL;
-
- /* ESC hide the interface, whereas SHIFT ESC, quit the programm: */
- if(code==27) cleanup(NULL,IconBase && !(ie.ie_Qualifier&IEQUALIFIER_LSHIFT) && !CloseQuit?-1:0);
-
- /* Tab, change the sorting method of chars: */
- else if(code=='\t')
- ((struct MenuItem *)ItemAddress(menu,MENUITEM(1,5,0)))->Flags ^= CHECKED,
- Handle_menu(26);
-
- /* Remove the last inputed char or clear all the string gadget: */
- else if(code=='\b' || code==127) {
- register WORD n=(code=='\b'?sti(gad)->NumChars-1:0);
- if(n<0) break;
- StrBuf[n]=0;
- RefreshGList(gad, window, NULL, 1);
- }}
- break;
- case GADGETUP:
- Handle_gadget( (struct Gadget *)message.IAddress );
- break;
-
- case REFRESHWINDOW:
- /* A minimized window has been poped-up: */
- if(window->Height>window->BorderTop) {
- Init_helpwin(window);
- if(NumChar>=0) Disp_charinfo(NumChar);
- Draw_ASCIIChart();
- }
- }
- /* Has the user hiden the window ? */
- if(window==NULL) goto Deb;
- }
- /* This reduces number of IDCMP MOUSEMOVE msg to process */
- if(drawit) Handle_box();
- }
- }
-